/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package futbol.tacticas.concursantes.aitkiar.aitutil;

import futbol.tacticas.SituacionJugadores;
import java.awt.Point;
import java.util.ArrayList;

/** Clase que representa el campo dividido en áreas.
 * 
 *  Se usa para calcular mejor los pases, los cambios en la estrategia, ...
 *
 * @author aitkiar
 */
public class Campo
{

    protected int lado;
    protected int ancho;
    protected int largo;
    protected int bola;
    protected int destinoBola;
    protected ZonaCampo[] zonas;
    protected Point puntoInterseccionBola = new Point();
    protected Point puntoDestinoBola = new Point();
    protected int jugadorMasCercanoBola = 0;
    protected Point contrarios[];
    protected int marcajes[];
    protected Point[] jugadores;
    private Jugador[] equipo;

    public Campo( int lado )
    {
        this.lado = lado;
        ancho = 240 / lado;
        largo = 320 / lado;
        zonas = new ZonaCampo[ancho * largo];
        for ( int columna = 0; columna < ancho; columna++ )
        {
            for ( int fila = 0; fila < largo; fila++ )
            {
                zonas[columna * largo + fila] = new ZonaCampo( lado * fila - 160,
                    lado * columna - 120, lado );
            }
        }
        marcajes = new int[11];
    }

    /** Actualiza el número de contrarios y jugadores en cada zona.
     * Identifica en que zona está la bola.
     * Identifica en que zona acabará la bola con la trayectoria actual.
     * 
     * @param sj
     */
    public void actualizar( SituacionJugadores sj )
    {
        Point bola = sj.getBola();
        Point destinoBola = Utils.posicionTrayectoriaBola( sj );
        ZonaCampo zona;
        contrarios = sj.getContrario();
        jugadores = sj.getMisJugadores();

        this.bola = -1;
        this.destinoBola = -1;

        for ( int i = 0; i < zonas.length; i++ )
        {
            zona = zonas[i];
            zona.contrariosDentro( contrarios );
            zona.jugadoresDentro( jugadores );
            if ( this.bola == -1 && zona.dentro( bola ) )
            {
                this.bola = i;
            }
            if ( this.destinoBola == -1 && zona.dentro( destinoBola ) )
            {
                this.destinoBola = i;
            }
        }

        puntoInterseccionBola = Utils.posicionTrayectoriaBola( sj, 14 );
        puntoDestinoBola = Utils.posicionTrayectoriaBola( sj, 5 ); 
        // consideramos cinco en lugar de cero para anticiparnos a posibles intercepciones.
        
        int distanciaMasCerca = 1000;
        
        for ( int i = 0; i < 11; i++ )
        {
            if ( Utils.distancia( jugadores[i], puntoInterseccionBola ) < distanciaMasCerca )
            {
                this.jugadorMasCercanoBola = i;
                distanciaMasCerca = ( int )Utils.distancia( jugadores[i], puntoInterseccionBola );
            }
            if ( Utils.distancia( jugadores[i], puntoDestinoBola ) < distanciaMasCerca )
            {
                this.jugadorMasCercanoBola = i;
                distanciaMasCerca = ( int )Utils.distancia( jugadores[i], puntoDestinoBola );
            }
        }
        
        int distanciaOptima = 1000;
        int jugadorCobertura = -1;
        boolean usado;
        
        // Actualizamos los marcajes según la posición x,y inicial de los jugadores.
        for ( int i = 10; i >= 0; i -- )
        {
            // Si la pelota retrocede y el contrario está más acá del centro del campo.
            if ( contrarios[i].x < 0 || destinoBola.x < bola.x )
            {
                jugadorCobertura = -1;
                
                for ( int j = 1; j < 11; j ++ )
                {
                    if ( equipo[j].defensivo && Utils.distancia( 
                        new Point( jugadores[j].x, jugadores[j].y ), contrarios[i]) < distanciaOptima )
                    {
                        usado = false;
                        for ( int k = 0; k < 11 && !usado; k ++ )
                        {
                            usado = marcajes[k] == j;
                        }
                        if ( !usado )
                        {
                            jugadorCobertura = j;
                            distanciaOptima = ( int ) Utils.distancia( new Point( jugadores[j].x, jugadores[j].y ),
                                contrarios[i]);
                        }
                    }
                }
                
                marcajes[i] = jugadorCobertura;
            }
        }
    }

    public int getZona( Point punto )
    {
        int x = (punto.x + 160) / lado;
        int y = (punto.y + 120) / lado;
        return largo * y + x;
    }

    public ZonaCampo[] getAdyacentes( Point punto )
    {
        return getAdyacentes( getZona( punto ) );
    }

    public ZonaCampo[] getAdyacentes( int zona )
    {
        ArrayList<ZonaCampo> resultado = new ArrayList<ZonaCampo>();

        int x = zona % largo;
        int y = zona / largo;

        for ( int j = -1; j <= 1; j++ )
        {
            for ( int i = -1; i <= 1; i++ )
            {
                if ( (x + i) >= 0 && (x + i) < largo && (y + j) >= 0 && (y + j) < ancho )
                {
                    resultado.add( zonas[(y + j) * largo + x + i] );
                }
            }
        }
        return resultado.toArray( new ZonaCampo[resultado.size()] );
    }

    /** Redondeamos el número de zonas considerando las que forman un "cuadrado" sin esquinas de lado 
     * igaul a : (( distancia / lado ) -1) * 2
     * 
     * @param zona
     * @param fuerza
     * @return
     */
    public ZonaCampo[] getZonasPase( int zona, int distancia )
    {
        ArrayList<ZonaCampo> resultado = new ArrayList<ZonaCampo>();

        int x = zona % largo;
        int y = zona / largo;

        int variacion = distancia / lado - 1;

        // Consideramos que siempre podemos pasar al menos dos zonas.
        if ( variacion < 2 )
        {
            variacion = 2;
        }

        for ( int i = -variacion; i <= variacion; i++ )
        {
            // lados superior e inferior
            if ( x + i >= 0 && x + i < largo )
            {
                if ( y - variacion >= 0 )
                {
                    resultado.add( zonas[(y - variacion) * largo + x + i] );
                }

                if ( y + variacion < ancho )
                {
                    resultado.add( zonas[(y + variacion) * largo + x + i] );
                }
            }

            //lados izquierdo y derecho
            if ( y + i >= 0 && y + i < ancho )
            {
                if ( x - variacion >= 0 )
                {
                    resultado.add( zonas[(y + i) * largo + x - variacion] );
                }

                if ( x + variacion < largo )
                {
                    resultado.add( zonas[(y + i) * largo + x + variacion] );
                }
            }
        }

        return resultado.toArray( new ZonaCampo[resultado.size()] );
    }

    public int getJugadorMasCercanoBola()
    {
        return jugadorMasCercanoBola;
    }

    public void setEquipo( Jugador[] equipo )
    {
        this.equipo = equipo;
    }
    
    public Point getMarcaje( int numero )
    {
        int contrario = -1;
        for ( int i = 0; i < 11 && contrario == -1; i ++ )
        {
            if ( marcajes[i] == numero )
            {
                contrario = i;
            }
        }
        if ( contrario != -1 )
        {
            return contrarios[ contrario ];
        }
        return null;
    }
}
